package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.dto.ContractPaymentScheduleCreateDTO;
import com.ruoyi.system.dto.ContractPaymentScheduleDTO;
import com.ruoyi.system.dto.ContractPaymentScheduleUpdateDTO;
import com.ruoyi.system.entity.ContractPaymentSchedule;
import com.ruoyi.system.mapper.ContractPaymentScheduleMapStruct;
import com.ruoyi.system.mapper.ContractPaymentScheduleMapper;
import com.ruoyi.system.service.ContractPaymentScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 合同付款周期服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContractPaymentScheduleServiceImpl extends ServiceImpl<ContractPaymentScheduleMapper, ContractPaymentSchedule> 
        implements ContractPaymentScheduleService {

    private final ContractPaymentScheduleMapper paymentScheduleMapper;

    @Override
    public List<ContractPaymentScheduleDTO> getByContractId(Long contractId) {
        log.info("查询合同付款周期列表，合同ID: {}", contractId);
        
        if (contractId == null) {
            throw new ServiceException("合同ID不能为空");
        }

        List<ContractPaymentSchedule> schedules = paymentScheduleMapper.selectByContractId(contractId);
        return ContractPaymentScheduleMapStruct.INSTANCE.toDTOList(schedules);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractPaymentScheduleDTO create(ContractPaymentScheduleCreateDTO dto) {
        log.info("创建付款周期，合同ID: {}, 分期: {}", dto.getContractId(), dto.getInstallment());

        // 验证分期期数是否重复
        validateInstallmentUnique(dto.getContractId(), dto.getInstallment(), null);

        ContractPaymentSchedule entity = ContractPaymentScheduleMapStruct.INSTANCE.toDO(dto);
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());

        boolean result = this.save(entity);
        if (!result) {
            throw new ServiceException("付款周期创建失败");
        }

        log.info("付款周期创建成功，ID: {}", entity.getId());
        return ContractPaymentScheduleMapStruct.INSTANCE.toDTO(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ContractPaymentScheduleDTO> createBatch(List<ContractPaymentScheduleCreateDTO> dtos) {
        log.info("批量创建付款周期，数量: {}", dtos.size());

        if (dtos.isEmpty()) {
            return new ArrayList<>();
        }

        // 验证所有分期期数是否重复
        for (ContractPaymentScheduleCreateDTO dto : dtos) {
            validateInstallmentUnique(dto.getContractId(), dto.getInstallment(), null);
        }

        List<ContractPaymentSchedule> entities = dtos.stream()
                .map(dto -> {
                    ContractPaymentSchedule entity = ContractPaymentScheduleMapStruct.INSTANCE.toDO(dto);
                    entity.setCreateTime(LocalDateTime.now());
                    entity.setUpdateTime(LocalDateTime.now());
                    return entity;
                })
                .collect(Collectors.toList());

        boolean result = this.saveBatch(entities);
        if (!result) {
            throw new ServiceException("批量创建付款周期失败");
        }

        log.info("批量创建付款周期成功，数量: {}", entities.size());
        return ContractPaymentScheduleMapStruct.INSTANCE.toDTOList(entities);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractPaymentScheduleDTO update(ContractPaymentScheduleUpdateDTO dto) {
        log.info("更新付款周期，ID: {}", dto.getId());

        // 验证付款周期是否存在
        ContractPaymentSchedule existing = this.getById(dto.getId());
        if (existing == null) {
            throw new ServiceException("付款周期不存在");
        }

        // 验证分期期数是否重复
        validateInstallmentUnique(existing.getContractId(), dto.getInstallment(), dto.getId());

        ContractPaymentSchedule entity = ContractPaymentScheduleMapStruct.INSTANCE.toDO(dto);
        entity.setUpdateTime(LocalDateTime.now());

        boolean result = this.updateById(entity);
        if (!result) {
            throw new ServiceException("付款周期更新失败");
        }

        log.info("付款周期更新成功，ID: {}", dto.getId());
        return ContractPaymentScheduleMapStruct.INSTANCE.toDTO(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Long id) {
        log.info("删除付款周期，ID: {}", id);

        if (id == null) {
            throw new ServiceException("付款周期ID不能为空");
        }

        boolean result = this.removeById(id);
        if (!result) {
            throw new ServiceException("付款周期删除失败");
        }

        log.info("付款周期删除成功，ID: {}", id);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByContractId(Long contractId) {
        log.info("删除合同所有付款周期，合同ID: {}", contractId);

        if (contractId == null) {
            throw new ServiceException("合同ID不能为空");
        }

        int result = paymentScheduleMapper.deleteByContractId(contractId);
        log.info("删除合同付款周期成功，合同ID: {}, 删除数量: {}", contractId, result);
        return result >= 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePaymentStatus(Long id, Integer paymentStatus, 
                                     LocalDate actualPaymentDate, 
                                     BigDecimal actualPaymentAmount) {
        log.info("更新付款状态，ID: {}, 状态: {}, 实际付款日期: {}, 实际付款金额: {}", 
                id, paymentStatus, actualPaymentDate, actualPaymentAmount);

        if (id == null) {
            throw new ServiceException("付款周期ID不能为空");
        }

        ContractPaymentSchedule entity = this.getById(id);
        if (entity == null) {
            throw new ServiceException("付款周期不存在");
        }

        entity.setPaymentStatus(paymentStatus);
        entity.setActualPaymentDate(actualPaymentDate);
        entity.setActualPaymentAmount(actualPaymentAmount);
        entity.setUpdateTime(LocalDateTime.now());

        boolean result = this.updateById(entity);
        if (!result) {
            throw new ServiceException("付款状态更新失败");
        }

        log.info("付款状态更新成功，ID: {}", id);
        return true;
    }

    @Override
    public BigDecimal getTotalPaymentAmount(Long contractId) {
        log.info("统计合同总付款金额，合同ID: {}", contractId);

        if (contractId == null) {
            return BigDecimal.ZERO;
        }

        BigDecimal totalAmount = paymentScheduleMapper.sumPaymentAmountByContractId(contractId);
        return totalAmount != null ? totalAmount : BigDecimal.ZERO;
    }

    @Override
    public BigDecimal getTotalActualPaymentAmount(Long contractId) {
        log.info("统计合同总已付款金额，合同ID: {}", contractId);

        if (contractId == null) {
            return BigDecimal.ZERO;
        }

        BigDecimal totalAmount = paymentScheduleMapper.sumActualPaymentAmountByContractId(contractId);
        return totalAmount != null ? totalAmount : BigDecimal.ZERO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ContractPaymentScheduleDTO> createDefaultPaymentSchedules(Long contractId, BigDecimal totalAmount) {
        log.info("创建默认付款周期，合同ID: {}, 总金额: {}", contractId, totalAmount);

        if (contractId == null || totalAmount == null) {
            throw new ServiceException("合同ID和总金额不能为空");
        }

        // 删除现有的付款周期
        deleteByContractId(contractId);

        // 创建默认的3期付款周期
        List<ContractPaymentScheduleCreateDTO> defaultSchedules = new ArrayList<>();
        LocalDate today = LocalDate.now();

        // 第一期：签约时付款30%
        ContractPaymentScheduleCreateDTO schedule1 = new ContractPaymentScheduleCreateDTO();
        schedule1.setContractId(contractId);
        schedule1.setPaymentMethod(2); // 银行转账
        schedule1.setInstallment(1);
        schedule1.setPaymentDate(today);
        schedule1.setPaymentAmount(totalAmount.multiply(new BigDecimal("0.30")));
        schedule1.setPaymentRemark("签约时付款");
        defaultSchedules.add(schedule1);

        // 第二期：工程进度50%时付款40%
        ContractPaymentScheduleCreateDTO schedule2 = new ContractPaymentScheduleCreateDTO();
        schedule2.setContractId(contractId);
        schedule2.setPaymentMethod(2); // 银行转账
        schedule2.setInstallment(2);
        schedule2.setPaymentDate(today.plusDays(30)); // 30天后
        schedule2.setPaymentAmount(totalAmount.multiply(new BigDecimal("0.40")));
        schedule2.setPaymentRemark("工程进度50%时付款");
        defaultSchedules.add(schedule2);

        // 第三期：工程完工验收后付款30%
        ContractPaymentScheduleCreateDTO schedule3 = new ContractPaymentScheduleCreateDTO();
        schedule3.setContractId(contractId);
        schedule3.setPaymentMethod(2); // 银行转账
        schedule3.setInstallment(3);
        schedule3.setPaymentDate(today.plusDays(60)); // 60天后
        schedule3.setPaymentAmount(totalAmount.multiply(new BigDecimal("0.30")));
        schedule3.setPaymentRemark("工程完工验收后付款");
        defaultSchedules.add(schedule3);

        return createBatch(defaultSchedules);
    }

    /**
     * 验证分期期数是否重复
     */
    private void validateInstallmentUnique(Long contractId, Integer installment, Long excludeId) {
        LambdaQueryWrapper<ContractPaymentSchedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ContractPaymentSchedule::getContractId, contractId)
                .eq(ContractPaymentSchedule::getInstallment, installment)
                .eq(ContractPaymentSchedule::getIsDeleted, 0);

        if (excludeId != null) {
            wrapper.ne(ContractPaymentSchedule::getId, excludeId);
        }

        long count = this.count(wrapper);
        if (count > 0) {
            throw new ServiceException("该合同已存在第" + installment + "期付款周期");
        }
    }
}
